import weka.core.*;
import weka.core.converters.*;
import weka.core.converters.ConverterUtils.DataSource;

import weka.classifiers.Classifier;
import weka.classifiers.trees.ADTree;
import weka.classifiers.trees.adtree.*;
import weka.attributeSelection.*;

import weka.experiment.InstanceQuery;
import weka.filters.unsupervised.attribute.Remove;
import weka.gui.treevisualizer.Node;
import weka.gui.treevisualizer.PlaceNode2;
import weka.gui.treevisualizer.TreeBuild;
import weka.gui.treevisualizer.TreeVisualizer;

import weka.classifiers.Evaluation;
import java.util.Random;


import java.util.Vector;

import javax.swing.JComponent;
import javax.swing.JFrame;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.io.*;
import java.net.URLConnection;


import java.net.URL;
import java.net.URLConnection;

public class Database {
	Instances data;	
	Instances filtered_data;
	Instances train;
	Instances complementTrain;
	Instances test;
	
	// telecharcher la base de donnees
	int loadDatabase(String url)
	{
		try
		{    
			DataSource source = new DataSource(url); 
			data = source.getDataSet();           
			data.setClassIndex(data.numAttributes() - 2);
			filtered_data = data;			
		}
		catch(Exception e)
		{
			e.printStackTrace();
			return 0;
		}
		return 1;  
	}
	
	// diviser la base de donnees en 2 parties : apprentissage et test
	void setTrain(int mode, double percent)
	{
		int trainSize = (int)(data.numInstances() * percent / 100);
	    int testSize = data.numInstances() - trainSize;
	    
		// mode = 0 : random
		if(mode == 0)
			filtered_data.randomize(new Random());
		
		if((mode==0) || (mode==1))
		{
			train = new Instances(filtered_data, 0, trainSize);
		    complementTrain = new Instances(filtered_data, trainSize, testSize); 
		}
		else
		{
			complementTrain = new Instances(filtered_data, 0, testSize);
		    train = new Instances(filtered_data, testSize, trainSize); 
		}
		
		System.out.println("Train size : " + train.numInstances());
	}
	
	// separer une partie de test
	void setTest(int mode, double percent)
	{
	    int testSize = (int)(data.numInstances() * percent / 100);
	    int trainSize= data.numInstances() - testSize;
	    
		switch(mode)
		{
		case 0: // not is in
			test = new Instances(complementTrain);
			break;
		case 1: // random
			data.randomize(new Random());
			System.out.println("Random percent : " + percent + " testsize : " + testSize );
			test = new Instances(filtered_data, 0, testSize); 
			break;
		case 2:	// first
			test = new Instances(filtered_data, 0, testSize); 
			break;
		case 3: // last
			test = new Instances(filtered_data, trainSize, testSize); 
			break;
		case 4: // learning set
			test = new Instances(train);
			break;			
		}
	}
	

	
	Vector<Attribute> getGoalAttributes()
	{
		Vector<Attribute> discretAttr = new Vector();
	    
	    for(int i=0; i< data.numAttributes(); i++)
	    {
	    	Attribute attr = data.attribute(i); 
	    	if(attr.isNominal())
	    		discretAttr.add(attr);    	
	    }
		return discretAttr;
	}
	
	
	Vector<Attribute> getAllAttributes()
	{
		Vector<Attribute> allAttr = new Vector();
	    
	    for(int i=0; i< data.numAttributes(); i++)
	    {
	    	Attribute attr = data.attribute(i); 
	    	allAttr.add(attr);    	
	    }
		return allAttr;
	}
	
	
	Vector getAllAttributesDescription()
	{
		Vector<Attribute> allAttr = getAllAttributes();
		Vector<String> des = new Vector();		
		
		for(int i=0; i<allAttr.size();i++)
		{
			String st = new String("");
			Attribute attr = allAttr.elementAt(i);
			st += attr.name();
			
			if(attr.isNominal())
			{
				st += " - symbolique - value : [ ";				
				for(int j=0; j < attr.numValues(); j++)
					st += attr.value(j) +", ";	
			}
			else
			{
				st += " - numerical - range : [ ";
				st += minValue(attr);
				st += ", ";			
				st += maxValue(attr);
			}			
			st += " ]";
			des.add(st);
		}
		return des;
	}
	
	double minValue(Attribute attr)
	{
		double min = 1000000.0;
		for(int i = 0; i<data.numInstances(); i++)
		{
			double value = data.instance(i).value(attr);
			if(min > value)
				min = value;
		}
		return min;
	}
	
	double maxValue(Attribute attr)
	{
		double max = -1000000.0;
		for(int i = 0; i<data.numInstances(); i++)
		{
			double value = data.instance(i).value(attr);
			if(max < value)
				max = value;
		}
		return max;
	}
	
	
	Vector getGoalAttributesDescription()
	{
		
		Vector<Attribute> goalAttr = getGoalAttributes();
		Vector<String> des = new Vector();
		
		for(int i=0; i<goalAttr.size();i++)
			des.add(goalAttr.elementAt(i).name());
		
		return des;
	}
	
	
	//======================================================================
	// FILTER CERTAINES ATTRIBUTES
	
	Vector<Attribute> getCandidatAttributes(Vector<Integer> index)
	{
		Vector<Attribute> allAttr = new Vector();
		for(int i=0; i< index.size(); i++)
		{
			int ind = index.elementAt(i).intValue();
			allAttr.add(data.attribute(ind));	
		}
		return allAttr;
	}
	
	
	Vector<String> scanCandidatAttributes(Vector<Attribute> candidatAttributes)
	{
		Vector<String> scan = new Vector();
		try
		{
			GainRatioAttributeEval evalGainRatio = new GainRatioAttributeEval();
		    evalGainRatio.buildEvaluator(train);
		    
	        for(int i=0; i<candidatAttributes.size(); i++)
	        {
	        	Attribute attr = candidatAttributes.elementAt(i);
	        	double gainRatio = evalGainRatio.evaluateAttribute(i);
	        	
	   		  	String st = attr.name() + " - gain info : " + gainRatio; 
	        	scan.add(st);
	        }
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
        return scan;
	}
	
	
	//======================================================================
	Vector<String> scanCandidatAttributesByIndex(Vector<Integer> index)
	{
		Vector<Attribute>candidatAttributes = getCandidatAttributes(index);
        return scanCandidatAttributes(candidatAttributes);
	}
	
	
	//======================================================================	
	// filter les attributes par l'indice
	
	void filterAttributes(Vector<Integer> index, Attribute goal)
	{
		String[] options = new String[2];
		options[0] = "-R";  		
		options[1] = "";	
		
		boolean goalInCandidat = false;		

		
		if(index.size()!= 0)
		{
			try
			{
			    int t = index.get(0);
		    	options[1] = String.valueOf(t+1);  
				if(data.attribute(t) == goal)
					goalInCandidat = true;
				
				for(int i=1; i< index.size(); i++)
				{
					if(i<index.size())
						options[1] += ",";
					
					t = index.get(i);
					
					if(data.attribute(t) == goal)
						goalInCandidat = true;
					options[1] = options[1] + String.valueOf(t+1); 		

				}
				
				if(goalInCandidat == false)				
					options[1] += ", " + (goal.index()+1);
					
				
				
				Remove remove = new Remove();                         // new instance of filter		   
			    remove.setOptions(options);                           // set options
			    remove.setInvertSelection(true);
			    remove.setInputFormat(data);                          // inform filter about dataset AFTER setting options

			    filtered_data = weka.filters.Filter.useFilter(data, remove);
			    
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}	    
		
	}
	
	Attribute setGoalAttribute(String name)
	{
		Attribute attr = data.attribute(name);	
		return attr;
	}
	
}
